package com.veer.shop.utils;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.veer.shop.config.Constants;
import com.veer.shop.mapper.AdminUserMapper;
import com.veer.shop.mapper.CustomerMapper;
import com.veer.shop.pojo.User;
import com.veer.shop.result.CustomerBaseResult;
import com.veer.shop.pojo.Token;

/**
 * JWT 加密工具类
 * 
 * @author WangBin
 * 2020年8月15日-下午1:46:48
 */
@Component
public class JwtUtil {
	
	@Autowired
	private AdminUserMapper adminUserMapper;
	@Autowired
	private CustomerMapper customerMapper;
	
	/**
	 * 生成 JWT token
	 * 
	 * @param userId
	 * @param secret
	 * @return
	 */
	public static Token generate(int userId, String secret) {
		Token token = new Token();
		try {
			// 过期时间戳
			long expiredTimestamp = DateTimeUtil.getCurrentTimeStamp() + Constants.JWT_TOKEN_LIFE_TIME;
			Date expiredAt = new Date(expiredTimestamp);
			
			// 设置算法对象 传入 密钥
			Algorithm algorithm = Algorithm.HMAC256(secret);
			
			// 设置头信息
			HashMap<String, Object> header = new HashMap<String, Object>();
			header.put("typ", Constants.JWT_TOKEN_HEAHER_TYPE);
			header.put("alg", Constants.JWT_TOKEN_HEAHER_ALG);
			
			String jwtToken = JWT.create().withHeader(header)
					.withClaim("user_id", userId)
					.withExpiresAt(expiredAt)
					.withIssuer(Constants.JWT_TOKEN_SIGN_ISSUER)
					.sign(algorithm);
			token.setExpiredAt(expiredTimestamp);
			token.setToken(jwtToken);
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		return token;
	}
	
	/**
	 * 解析 JWT token
	 * 
	 * @param token
	 * @param secret
	 */
	public static HashMap<String, Object> parseJwt(String token, String secret) {
		HashMap<String, Object> verifierMap = new HashMap<String, Object>();
		try {
			// 算法对象
			Algorithm algorithm = Algorithm.HMAC256(secret);
			// JWT验证器
			JWTVerifier verifier = JWT.require(algorithm).build();
			DecodedJWT jwt = verifier.verify(token);
			// 解析得到用户名
			verifierMap.put("user_id", jwt.getClaim("user_id").asInt());
			// 解析得到过期时间
			verifierMap.put("expired_at", jwt.getExpiresAt());
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		return verifierMap;
	}
	
	/**
	 * 校验 admin token正确
	 * 
	 * @param jwtStr
	 * @return
	 */
	public boolean verifyAdminJwt(String jwtStr) {
		// 得到 token
		String tokenStr = jwtStr.replace("Bearer ", "");
		// 解析 token
		Map<String, Object> parseMap = JwtUtil.parseJwt(tokenStr, Constants.JWT_PASSOWRD_SECRET);
		// 获取 user_id
		if(parseMap.containsKey("user_id") && parseMap.containsKey("expired_at")) {
			// 根据用户ID查询用户是否存在
			User adminUserEntity = adminUserMapper.selectAdminUserById(Integer.parseInt(parseMap.get("user_id").toString()));
			if(adminUserEntity != null) {
				// 校验token是否过期
				long currentTimeStamp = DateTimeUtil.getCurrentTimeStamp();
				SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String expiredAt = sdf.format((Date)parseMap.get("expired_at"));
				DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
				LocalDateTime localDateTime = LocalDateTime.parse(expiredAt, ftf);
				return LocalDateTime.from(localDateTime).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() > currentTimeStamp;
			}
		}
		// 校验失败
		return false;
	}
	
	/**
	 * 校验 cusotmer token正确
	 * 
	 * @param jwtStr
	 * @return
	 */
	public boolean verifyCustomerJwt(String jwtStr) {
		// 得到 token
		String tokenStr = jwtStr.replace("Bearer ", "");
		// 解析 token
		Map<String, Object> parseMap = JwtUtil.parseJwt(tokenStr, Constants.JWT_PASSOWRD_SECRET);
		// 获取 user_id
		if(parseMap.containsKey("user_id") && parseMap.containsKey("expired_at")) {
			// 根据ID查询会员是否存在
			CustomerBaseResult customer = customerMapper.getCustomerById(Integer.parseInt(parseMap.get("user_id").toString()));
			if(customer != null) {
				// 校验token是否过期
				SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				sdf.format((Date)parseMap.get("expired_at"));
				long currentTimeStamp = DateTimeUtil.getCurrentTimeStamp();
				return (long) parseMap.get("expired_at") > currentTimeStamp;
			}
		}
		// 校验失败
		return false;
	}
}
